﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using JY.IOC.Configuration.Elements;
using JY.IOC.Configuration.Extensions;
using Microsoft.Extensions.DependencyInjection;

namespace JY.IOC.Configuration
{
    /// <summary>
    /// 配置文件注册扩展
    /// </summary>
    public static class IocRegister
    {
        #region # 注册服务 —— static void Register(this IServiceCollection serviceCollection)
        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="serviceCollection">容器建造者</param>
        public static void RegisterServices(this IServiceCollection serviceCollection)
        {
            RegisterInterfaceAssemblies(serviceCollection);
            RegisterImplementsAssemblies(serviceCollection);
            RegisterAssemblies(serviceCollection);
            RegisterBaseAssemblies(serviceCollection);
            RegisterWcfInterfaces(serviceCollection);

            RegisterInterfaceTypes(serviceCollection);
            RegisterImplementsTypes(serviceCollection);
            RegisterBaseTypes(serviceCollection);
        }
        #endregion

        #region # 重新创建Wcf通道 —— static void WcfReCreateChannel()
        private static List<Type> WcfServiceTypes;
        private static Dictionary<Type, bool> ReCreateChannelTypes;
        /// <summary>
        /// 第一次创建Wcf通道时间
        /// </summary>
        public static DateTime? FirstCreateChannelTime { get; set; }

        /// <summary>
        /// 重新创建Wcf通道
        /// </summary>
        public static void WcfReCreateChannel()
        {
            ReCreateChannelTypes = WcfServiceTypes.ToDictionary(x => x, x => false);
            FirstCreateChannelTime = null;
        }
        #endregion
        //Private

        #region # 注册接口程序集 —— static void RegisterInterfaceAssemblies(IServiceCollection...
        /// <summary>
        /// 注册接口程序集
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterInterfaceAssemblies(this IServiceCollection builder)
        {
            foreach (AssemblyElement element in IocSection.Section.OnlyRegisterInterfacesAssemblies)
            {
                Assembly currentAssembly = Assembly.Load(element.Name.Trim());
                IEnumerable<Type> types = currentAssembly.GetTypes().Where(x => !x.IsAbstract && !x.IsInterface && x.IsPublic);
                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                foreach (Type type in types)
                {
                    foreach (Type @interface in type.GetInterfaces())
                    {
                        ServiceDescriptor descriptor = new ServiceDescriptor(@interface, type, lifetimeMode);
                        builder.Add(descriptor);
                    }
                }
            }
        }
        #endregion

        #region # 注册接口实现程序集 —— static void RegisterImplementsAssemblies(IServiceCollection builder)
        /// <summary>
        /// 注册接口实现程序集
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterImplementsAssemblies(IServiceCollection builder)
        {
            foreach (AssemblyElement element in IocSection.Section.OnlyRegisterImplementsAssemblies)
            {
                Assembly currentAssembly = Assembly.Load(element.Name.Trim());
                IEnumerable<Type> types = currentAssembly.GetTypes().Where(x => !x.IsAbstract && !x.IsInterface && x.IsPublic);
                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                foreach (Type type in types)
                {
                    ServiceDescriptor descriptor = new ServiceDescriptor(type, type, lifetimeMode);
                    builder.Add(descriptor);
                }
            }
        }
        #endregion

        #region # 注册程序集 —— static void RegisterAssemblies(IServiceCollection builder)
        /// <summary>
        /// 注册程序集
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterAssemblies(IServiceCollection builder)
        {
            foreach (AssemblyElement element in IocSection.Section.AllRegisterAssemblies)
            {
                Assembly currentAssembly = Assembly.Load(element.Name.Trim());
                IEnumerable<Type> types = currentAssembly.GetTypes().Where(x => !x.IsAbstract && !x.IsInterface && x.IsPublic);
                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                foreach (Type type in types)
                {
                    if (type.GetInterfaces().Any())
                    {
                        //存在接口注册接口
                        foreach (Type @interface in type.GetInterfaces())
                        {
                            ServiceDescriptor descriptorInterface = new ServiceDescriptor(@interface, type, lifetimeMode);
                            builder.Add(descriptorInterface);
                        }
                    }
                    //注册类
                    ServiceDescriptor descriptor = new ServiceDescriptor(type, type, lifetimeMode);
                    builder.Add(descriptor);
                }
            }
        }
        #endregion

        #region # 注册基类程序集 —— static void RegisterAssemblies(IServiceCollection builder)
        /// <summary>
        /// 注册基类程序集
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterBaseAssemblies(IServiceCollection builder)
        {
            foreach (AssemblyElement element in IocSection.Section.AllRegisterBaseAssemblies)
            {
                Assembly currentAssembly = Assembly.Load(element.Name.Trim());
                IEnumerable<Type> types = currentAssembly.GetTypes().Where(x => !x.IsAbstract && !x.IsInterface && x.IsPublic);
                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                foreach (Type type in types)
                {
                    //注册类
                    ServiceDescriptor descriptor = new ServiceDescriptor(type.BaseType, type, lifetimeMode);
                    builder.Add(descriptor);
                }
            }
        }
        #endregion

        #region # 注册WCF接口列表 —— static void RegisterWcfInterfaces(IServiceCollection builder)
        /// <summary>
        /// 注册WCF接口列表
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterWcfInterfaces(IServiceCollection builder)
        {
            foreach (AssemblyElement element in IocSection.Section.WcfRegisterInterfacesAssemblies)
            {
                //加载程序集
                Assembly wcfInterfaceAssembly = Assembly.Load(element.Name);

                //获取WCF接口类型集
                WcfServiceTypes = wcfInterfaceAssembly.GetTypes().Where(type => type.IsInterface).ToList();

                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                WcfReCreateChannel();
                //注册WCF接口
                foreach (Type type in WcfServiceTypes)
                {
                    var channelFactoryMakeGenericType = typeof(ChannelFactory<>).MakeGenericType(type);
                    object[] parameters = { type.FullName };
                    var channelFactory = Activator.CreateInstance(channelFactoryMakeGenericType, parameters);// 创建类的实例 
                    var createChannel = channelFactoryMakeGenericType.GetMethod("CreateChannel",new Type[] {});
                    var channel = createChannel?.Invoke(channelFactory, null);

                    ServiceDescriptor descriptor = new ServiceDescriptor(type, factory =>
                    {
                        //此处每次ResolveMediator.Resolve<T>()时都触发，PreCall（Transient）时则每次都创建新的通道
                        if (lifetimeMode == ServiceLifetime.Transient || !ReCreateChannelTypes[type])
                        {
                            channel = createChannel?.Invoke(channelFactory, null);
                            ReCreateChannelTypes[type] = true;
                            if (FirstCreateChannelTime == null)
                            {
                                FirstCreateChannelTime = DateTime.Now;
                            }
                        }

                        return channel;
                    }, lifetimeMode);

                    builder.Add(descriptor);
                }
            }
        }
        #endregion


        #region # 注册接口类型 —— static void RegisterInterfaceTypes(IServiceCollection builder)
        /// <summary>
        /// 注册接口类型
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterInterfaceTypes(IServiceCollection builder)
        {
            foreach (TypeElement element in IocSection.Section.RegisterInterfaceTypes)
            {
                Assembly currentAssembly = Assembly.Load(element.Assembly.Trim());
                Type type = currentAssembly.GetType(element.Name.Trim());

                #region # 验证类型

                if (type == null)
                {
                    throw new NullReferenceException($"程序集\"{element.Assembly.Trim()}\"中不存在类型\"{element.Name.Trim()}\"！");
                }

                #endregion

                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();

                foreach (Type @interface in type.GetInterfaces())
                {
                    ServiceDescriptor descriptor = new ServiceDescriptor(@interface, type, lifetimeMode);
                    builder.Add(descriptor);
                }
            }
        }
        #endregion

        #region # 注册接口实现类型 —— static void RegisterImplementsTypes(IServiceCollection builder)
        /// <summary>
        /// 注册接口实现类型
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterImplementsTypes(IServiceCollection builder)
        {
            foreach (TypeElement element in IocSection.Section.RegisterTypes)
            {
                Assembly currentAssembly = Assembly.Load(element.Assembly.Trim());
                Type type = currentAssembly.GetType(element.Name.Trim());

                #region # 验证类型

                if (type == null)
                {
                    throw new NullReferenceException($"程序集\"{element.Assembly.Trim()}\"中不存在类型\"{element.Name.Trim()}\"！");
                }

                #endregion

                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();
                ServiceDescriptor descriptor = new ServiceDescriptor(type, type, lifetimeMode);
                builder.Add(descriptor);
            }
        }
        #endregion

        #region # 注册基类类型 —— static void RegisterBaseTypes(IServiceCollection builder)
        /// <summary>
        /// 注册基类类型
        /// </summary>
        /// <param name="builder">容器建造者</param>
        private static void RegisterBaseTypes(IServiceCollection builder)
        {
            foreach (TypeElement element in IocSection.Section.RegisterBaseTypes)
            {
                Assembly currentAssembly = Assembly.Load(element.Assembly.Trim());
                Type type = currentAssembly.GetType(element.Name.Trim());

                #region # 验证类型

                if (type == null)
                {
                    throw new NullReferenceException($"程序集\"{element.Assembly.Trim()}\"中不存在类型\"{element.Name.Trim()}\"！");
                }

                #endregion

                ServiceLifetime lifetimeMode = element.LifetimeMode.ToLifetime();
                ServiceDescriptor descriptor = new ServiceDescriptor(type.BaseType, type, lifetimeMode);
                builder.Add(descriptor);
            }
        }
        #endregion
    }
}
